using System;
using System.Collections.Generic;
using System.Reflection;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Microsoft.Practices.Unity.Interception
{
    [TestClass]
    public class RefParametersVirtualInterceptorTest
    {
        static T WrapAndCreateType<T>(IEnumerable<KeyValuePair<MethodBase, List<IInterceptionHandler>>> handlers,
                                      params object[] ctorArgs)
        {
            Type wrappedType = VirtualInterceptor.WrapClass(typeof(T));
            ILEmitProxy proxy = new ILEmitProxy(handlers);
            List<object> wrappedCtorArgs = new List<object> { proxy };
            wrappedCtorArgs.AddRange(ctorArgs);
            return (T)Activator.CreateInstance(wrappedType, wrappedCtorArgs.ToArray());
        }

        [TestMethod]
        public void RefClassParameter()
        {
            RecordingHandler handler = new RecordingHandler();
            MethodBase method = typeof(SpyRef).GetMethod("RefClassParameter");
            Dictionary<MethodBase, List<IInterceptionHandler>> dictionary = new Dictionary<MethodBase, List<IInterceptionHandler>>();
            List<IInterceptionHandler> handlers = new List<IInterceptionHandler> { handler };
            dictionary.Add(method, handlers);

            SpyRef result = WrapAndCreateType<SpyRef>(dictionary);
            string refValue = "Hello, ";
            result.RefClassParameter(ref refValue);

            Assert.AreEqual("Hello, world!", refValue);
        }

        [TestMethod]
        public void RefValueType()
        {
            RecordingHandler handler = new RecordingHandler();
            MethodBase method = typeof(SpyRef).GetMethod("RefValueType");
            Dictionary<MethodBase, List<IInterceptionHandler>> dictionary = new Dictionary<MethodBase, List<IInterceptionHandler>>();
            List<IInterceptionHandler> handlers = new List<IInterceptionHandler> { handler };
            dictionary.Add(method, handlers);

            SpyRef result = WrapAndCreateType<SpyRef>(dictionary);
            int refValue = 21;
            result.RefValueType(ref refValue);

            Assert.AreEqual(42, refValue);
        }

        public class SpyRef
        {
            public virtual void RefClassParameter(ref string value)
            {
                value += "world!";
            }

            public virtual void RefValueType(ref int value)
            {
                value *= 2;
            }
        }
    }
}